#pragma once
#include <string>
#include <cstddef> // std::size_t
#include <boost/date_time/posix_time/posix_time.hpp>
/*
 在 C++ 中，要使用 ODB 将类声明为持久化类，需要包含 ODB 的核心头文
件，并使用 #pragma db object 指令
 #pragma db object 指示 ODB 编译器将 person 类视为一个持久化类。
*/
#include <odb/core.hxx>
#include <odb/nullable.hxx>


#pragma db object 
class Student
{
public:
    Student(){}
    Student(unsigned long sn, const std::string& name, unsigned short age, unsigned long cid)
    :_sn(sn), _name(name), _age(age), _classes_id(cid)
    {}

    void sn(unsigned long num)
    {
        _sn = num;
    }

    unsigned long sn()
    {
        return _sn;
    }

    void name(const std::string& name)
    {
        _name = name;
    }
    std::string name()
    {
        return _name;
    }

    void age(unsigned short age)
    {
        _age = age;
    }
    odb::nullable<unsigned short> age()
    {
        return _age;
    }

    void classes_id(unsigned long num)
    {
        _classes_id = num;
    }

    unsigned long classes_id()
    {
        return _classes_id;
    }

private:
    //成员变量_id是一个私有成员需要将odb::access 设置为友元类
    friend class odb::access;
    #pragma db id auto      //设置为自增主键
    unsigned long _id;
    #pragma db unique       //设置为唯一键
    unsigned long _sn;
    std::string _name;
    odb::nullable<unsigned short> _age;
    #pragma db index        //设置为普通索引
    unsigned long _classes_id;
};

#pragma db object
class Classes
{
public:
    Classes(){}
    Classes(const std::string& name)
    :_name(name)
    {}
    void name(const std::string& name)
    {
        _name = name;
    }
    std::string name()
    {
        return _name;
    }
private:
    //成员变量_id是一个私有成员需要将odb::access 设置为友元类
    friend class odb::access;
    #pragma db id auto
    unsigned long _id;
    std::string _name;
};

//查询所有的学生信息，并显示班级名称---需要进行多表联合查询
#pragma db view object(Student)\
                object(Classes = classes : Student::_classes_id == classes::_id)\
                query((?))  //这个是联合查询过程中的一个自定义查询条件，其中的？可以用来接收一个外部条件;  Classes = classes表示起别名，之后的查询中要使用别名；
struct classes_student  //view视图需要关联一个对象，这里需要定义这个对象
{
    #pragma db column(Student::_id)     //需要告诉该结构中的成员对应联合查询表中的哪些字段，这里就表示当前表中的_id字段关联的Student表中的_id 字段
    unsigned long id;
    #pragma db column(Student::_sn)
    unsigned long sn;
    #pragma db column(Student::_name)
    std::string name;
    #pragma db column(Student::_age)
    odb::nullable<unsigned short> age;
    #pragma db column(classes::_name)   //在上面起了别名之后再这里关联的时候要使用别名
    std::string classes_name;  //对应的班级名称
};

//只查询学生姓名---根据类来查询的时候针对的是所有字段，当进行某个单独的字段查询的时候类中提供的查询是无法满足的，
//因为类提供的查询是针对类中所有字段的查询，所以需要视图和自定义查询来组合使用查询某个字段了；(?) 这个是外部调用时传入的过滤条件
#pragma db view query("select name from Student WHERE " + (?))
struct all_name
{
    std::string name;
};

//odb 编译：odb -d mysql --generate-query --generate-schema --profile boost/date-time student.hxx